<?php

declare(strict_types=1);

namespace app\admin\service;

use app\api\exception\ThrowException;
use app\admin\model\Invoice as InvoiceModel;
use app\admin\model\Images as ImagesModel;
use app\common\InventoryChangeRecord;
use think\facade\Db;
use app\common\service\CompleteNotificationService;
use think\facade\Log;


class Invoice extends BaseService
{

    protected $return;
    protected $validate;
    protected $model;
    public function __construct()
    {
        parent::__construct();
        $this->model = new InvoiceModel();
        $this->return = [
            'code' => 500001,
            'data' => [],
            'message' => ''
        ];
    }



    /**
     * @describe
     * @author: Bobo
     * @date: 2025-02-13 11:03:36
     * @param [type] @required
     * @return Renderable
     */
    public function getFieldEnum($field = 'all')
    {

        $res = $this->model->getFieldEnum($field);

        $invoice_no = $this->model->whereLike('invoice_no',  'IVO.' . date('Ymd') . '%')->order('invoice_no', 'desc')->field('invoice_no')->find();

        if ($invoice_no) {
            $dotPosition = strrpos($invoice_no['invoice_no'], '.');
            $prefix = substr($invoice_no['invoice_no'], 0, $dotPosition + 1);
            $numberPart = substr($invoice_no['invoice_no'], $dotPosition + 1);
            $number = (int)$numberPart;
            // 数字部分加 1
            $newNumber = $number + 1;
            // 格式化数字部分，保持和原字符串相同的长度
            $formattedNewNumber = sprintf('%0' . strlen($numberPart) . 'd', $newNumber);
            // 拼接新的字符串
            $res['invoice_no'] = $prefix . $formattedNewNumber;
        } else {
            $invoice_no = 1;
            $res['invoice_no'] = 'IVO.' . date('Ymd') . str_pad(strval($invoice_no), 4, '0', STR_PAD_LEFT);;
        }



        return [
            'code' => 0,
            'data' => $res
        ];
    }
    /**
     * 审核订单开票信息
     * @param array $data 开票信息的数据
     */
    public function check($data)
    {
        if (!isset($data['id']) || !$data['id'] || !isset($data['status']) || !$data['status']) {
            return ['code' => 100001, 'message' => '参数错误'];
        }
        $exists = $this->model::where([
            'id' => $data['id'],
            'status' => 1,
            'is_del' => 0
        ])->find();
        if (!$exists) {
            return ['code' => 400000, 'message' => '发票不存在或者状态不对']; // 如果发票编号已存在，返回错误信息
        }
        $status = $data['status'] == 1 ? 10 : 30;
        $this->model::startTrans();
        try {
            $this->model::where([
                'id' => $data['id'],
            ])->update(['status' => $status]);
            if ($status == 30) {
                $this->model->name('order_payment')->whereIn('id', $exists->payment_ids)->update(['invoice_status' => 10]);
            }
            $approverWhere = [
                'child_entity_id' => $data['id'],
                'business_module' => 'invoice',
                'child_business_module' => 'invoice',
                'operate' => '发票-创建',

            ];
            $this->logger->updateApprover($approverWhere,$data['operator_id']);
            $this->logger->logOperation($data['id'], 'invoice', $status ==10 ?'发票-审核通过':'发票-审核驳回', '订单开票信息创建');
            $this->model::commit(); // 提交事务
            return ['code' => 0]; // 返回成功信息
        } catch (\Throwable $th) {
            // 如果发生异常，回滚事务
            $this->model::rollback();
            // 返回错误信息
            return ['code' => 500001, 'message' => '服务器内部错误：' . $th->getMessage()];
        }
    }
    /**
     * 撤销
     * @param array $data 开票信息的数据
     */
    public function cancel($param)
    {

        $where = [['is_del', '=', '0'], ['id', '=', $param['id']],['status', '=',1],['creator','=',$param['operator_id']]];
        $invoice =  $this->model::where($where)->find();
        if (!$invoice) {
            return ['code' => 500001, 'message' => '获取发票信息失败！'];
        }
        $update =  $this->model::where($where)->update(['is_del' => time(),'status'=>30]);
        if(!$update){
            return ['code' => 500001, 'message' => '撤销失败'];
        }
        $this->logger->logOperation($invoice->id, 'invoice', '发票-取消', '订单开票信息创建取消'); // 记录操作日志
        return ['code' => 0, 'message' => 'success'];

    }

    /**
     * 创建订单开票信息
     * @param array $data 开票信息的数据
     */
    public function create($data)
    {
        // 开始事务
        $this->model::startTrans();

        try {
            // 检查发票编号是否已存在
            $exists = $this->model::where([
                'invoice_no' => $data['invoice_no'],
                'is_del' => 0
            ])->find();

            if ($exists) {
                return ['code' => 200001, 'message' => '发票编号已存在']; // 如果发票编号已存在，返回错误信息
            }

            $data['status'] = 1;    // 设置状态为已开票

            if ($data['payment_ids']) {
                $this->model->name('order_payment')->whereIn('id', $data['payment_ids'])->update(['invoice_status' => 20]); // 如果有支付记录，更新支付状态为开票中
            }

            // 创建新的发票记录
            $res = $this->model::create($data);
            if ($res && $res->id) {
                $this->model::commit(); // 提交事务
                $this->logger->logOperation($res->id, 'invoice', '发票-创建', '订单开票信息创建',1,'invoice',$res->id,'20,21'); // 记录操作日志

                try {
                    $notificationService = new CompleteNotificationService();
                    $notificationService->send('invoice_created', ['id' => $res->id]);
                } catch (\Exception $e) {
                    Log::error(
                        '创建发票通知发送失败: 发票编号: ' . $res->invoice_no . ' 错误信息: ' . $e->getMessage() .
                        ' | 文件：' . $e->getFile() .
                        ' | 行号：' . $e->getLine()
                    );
                }

                return ['code' => 0]; // 返回成功信息
            } else {
                // 如果创建失败，回滚事务
                $this->model::rollback();
                // 返回错误信息
                return ['code' => 500001, 'message' => '发票创建失败'];
            }
        } catch (\Throwable $th) {
            // 如果发生异常，回滚事务
            $this->model::rollback();
            // 返回错误信息
            return ['code' => 500001, 'message' => '服务器内部错误：' . $th->getMessage()];
        }
    }
    /**
     * @describe
     * @author: Bobo
     * @date: 2025-02-07 17:24:24
     * @param [type] @required
     * @return Renderable
     */
    public function getList(int $page = 1, int $limit = 10, array $where = [], $field = "*", $operator_id = 0)
    {


        try {

            if (isset($where['order_no']) && $where['order_no']) {
                $order_where['order_category'] = 'order' == $where['order_type'] ? 'order' : 'wholesal';
                $orderResult = $this->model->name("order")
                    ->whereLike('order_no',  '%' . $where['order_no'] . '%')
                    ->where('is_del', 0)
                    ->where($order_where)
                    ->field('id')
                    ->select()
                    ->toArray();
                if ($orderResult) {
                    $where[] = ['order_id', 'in', implode(',', array_column($orderResult, 'id'))];
                }
                unset($where['order_no']);
            }


            $query =  $this->model->where($where);
            if (!isSuperAdmin($operator_id)) { // 非超级管理员
                $operatorService = new Operator();
                $userResult = $operatorService->getBelongCustomers($operator_id);
                if (0 == $userResult['code']) {
                    if (1 == $userResult['data']['order_range']) {
                        $query->whereIn('customer_id', $userResult['data']['customer_ids']);
                    }
                } else {
                    $query->whereIn('customer_id', [0]);
                }
            }
            $total = $query->count();

            if ($total <= 0) {
                $return['code'] = 0;
            } else {
                $list = $query
                    ->field($field)
                    ->page($page, $limit)
                    ->order('id desc')
                    ->select()
                    ->toArray();
                // 获取所有需要的数据
                $customerIds = array_filter(array_column($list, 'customer_id'));  // 提取所有 customer_id
                $orderIds = implode(',', array_column($list, 'order_id'));  // 提取所有 order_id

                $paymentIds = array_filter(array_column($list, 'payment_ids'));  // 提取所有 payment_ids

                // 一次性查询所有 customer_option
                $customers = [];
                if ($customerIds) {
                    $customers = $this->model->name('customer')
                        ->whereIn('id', $customerIds)
                        ->field('id as value, cusname as label')
                        ->select()
                        ->toArray();
                    $customers = array_column($customers, null, 'value'); // 按照 customer_id 重新索引
                }

                // 一次性查询所有 order_option
                $orders = [];
                if ($orderIds) {
                    $orders = $this->model->name('order')
                        ->where('id', 'in', $orderIds)
                        ->field('id as value, order_no as label')
                        ->select()
                        ->toArray();
                    $orders = array_column($orders, null, 'value'); // 按照 order_id 重新索引

                    // // 需要查询 wholesal_order 表中的 order_option
                    // $wholesaleOrders = $this->model->name('wholesal_order')
                    //     ->whereIn('id', $orderIds)
                    //     ->field('id as value, order_no as label')
                    //     ->select()
                    //     ->toArray();
                    // $wholesaleOrders = array_column($wholesaleOrders, null, 'value'); // 按照 order_id 重新索引
                }

                // 一次性查询所有 payment_option
                $paymentOptions = [];
                if ($paymentIds) {
                    $paymentIdsArr = array_unique(explode(',', implode(',', $paymentIds)));  // 合并所有 payment_ids 并去重
                    $paymentOptions = $this->model->name('order_payment')
                        ->whereIn('id', $paymentIdsArr)
                        ->field('id as value, id as label')
                        ->select()
                        ->toArray();
                    $paymentOptions = array_column($paymentOptions, null, 'value'); // 按照 payment_id 重新索引
                }

                // 循环处理数据
                foreach ($list as $key => &$value) {
                    if ($value['customer_id'] && isset($customers[$value['customer_id']])) {
                        $value['customer_option'] = $customers[$value['customer_id']];
                    }

                    if ($value['order_id']) {
                        $order_ids = explode(',', $value['order_id']);

                        // $tableName = $value['order_type'] == 'order' ? $orders : $wholesaleOrders;
                        foreach ($order_ids  as $order_no) {
                            if (isset($orders[$order_no])) {
                                $value['order_option'][] = $orders[$order_no];
                            }
                        }
                    }

                    if ($value['payment_ids']) {
                        $payment_idarr = explode(',', $value['payment_ids']);
                        $value['payment_option'] = [];
                        foreach ($payment_idarr as $payment_id) {
                            if (isset($paymentOptions[$payment_id])) {
                                $value['payment_option'][] = $paymentOptions[$payment_id];
                            }
                        }
                    }
                }

                $return['code'] = 0;
                $return['data'] = ['list' => $list, 'total' => $total];
            }
        } catch (\Throwable $th) {
            $return['message'] = 'Failed to retrieve list. ' . $th->getMessage();
            $return['code'] = 500001;
        }
        return $return;
    }

    /**
     * @describe
     * @author: Bobo
     * @date: 2025-02-13 13:16:01
     * @param [type] @required
     * @return Renderable
     */
    public function getOne($id)
    {
        $res = $this->model->where('id', $id)->find()->toArray();
        $imagesModel = new ImagesModel();
        if ($res['applicant']) {
            $res['applicant_option'] = $this->model->name('operator')->where('id', $res['applicant'])->field('id as value , cname as label')->select();
        }
        if ($res['customer_id']) {
            $res['customer_option'] = $this->model->name('customer')->where('id', $res['customer_id'])->field('id as value , cusname as label')->select();
        }
        if ($res['order_id']) {
            $res['order_option'] = $this->model->name('order')->where('id', 'in', $res['order_id'])->field('id as value , order_no as label')->select();
        }
        if ($res['payment_ids']) {
            $payment_idarr = explode(',', $res['payment_ids']);
            $res['payment_option'] = $this->model->name('order_payment')->where('id', 'in', $payment_idarr)->field('id as value , id as label')->select();
        }
        if ($res['attach']) {
            $res['attach_list'] = $imagesModel->getImagesByIds($res['attach']);
        }
        if ($res['invoice_attach']) {
            $res['invoice_attach_list'] = $imagesModel->getImagesByIds($res['invoice_attach']);
        }

        if ($res) {
            return ['code' => 0, 'data' => $res];
        } else {
            return ['code' => 400000, 'message' => '未找到对应数据'];
        }
    }

    /**
     * @describe
     * @author: Bobo
     * @date: 2025-02-07 17:41:36
     * @param [type] @required
     * @return Renderable
     */
    public function update($where, $data)
    {
        if (!$where) {
            return ['code' => 200001, 'message' => '缺少必要参数'];
        }

        $res = $this->model->where($where)->find();
        // 开始事务
        $this->model::startTrans();

        try {
            if (!$res) {
                return ['code' => 400000, 'message' => '未找到对应数据'];;
            }
            if ($res->payment_ids) {
                $this->model->name('order_payment')->whereIn('id', $res->payment_ids)->update(['invoice_status' => 10]); // 如果有支付记录，更新支付状态为开票中
            }
            foreach ($data as $key => $value) {
                if ($res->$key != $value) {
                    $res->$key = $value;
                }
            }

            $exists = $this->model->where('is_del', 0)->where('id', '<>', $res->id)->where([
                'invoice_no' => $data['invoice_no'],
                'is_del' => 0
            ])->find();

            if ($exists) {
                return ['code' => 200001, 'message' => '发票编号已存在'];
            }
            if ($data['payment_ids']) {
                $this->model->name('order_payment')->whereIn('id', $data['payment_ids'])->update(['invoice_status' => 20]); // 如果有支付记录，更新支付状态为开票中
            }
            $result = $res->save();

            if ($result) {
                $this->logger->logOperation($res->id, 'invoice', '发票-编辑', '订单开票信息修改');
                $this->model::commit(); // 提交事务

                return ['code' => 0];
            } else {
                $this->model::rollback();
                return ['code' => 500001];
            }
        } catch (\Throwable $th) {
            // 如果发生异常，回滚事务
            $this->model::rollback();
            // 返回错误信息
            return ['code' => 500001, 'message' => '服务器内部错误：' . $th->getMessage()];
        }
    }


    /**
     * @describe 上传发票
     * @author: Bobo
     * @date: 2025-02-14 16:30:27
     * @param [type] @required
     * @return Renderable
     */

    public function uploadInvoice($where, $data)
    {
        if (!$where) {
            return ['code' => 200001, 'message' => '缺少必要参数'];
        }
        $res = $this->model->where($where)->where(['is_del' => 0])->find();

        if (!$res) {
            return  ['code' => 400000, 'message' => '未找到对应数据'];;
        }
        foreach ($data as $key => $value) {
            if ($res->$key != $value) {
                $res->$key = $value;
            }
        }
        Db::startTrans();

        $result = $res->save();
        try {
            if ($result) {
                $resultUpdate  = $this->model::name('order_payment')
                    ->where('id', 'in', $res['payment_ids'])
                    ->update([
                        'invoice_status' => 40,
                        'update_time' => date('Y-m-d H:i:s', time())
                    ]);

                if ($resultUpdate) {

                    Db::commit();
                    try {
                        $notificationService = new CompleteNotificationService();
                        $notificationService->send('invoice_pass', ['id' => $res->id]);
                    } catch (\Exception $e) {
                        // 通知发送失败不影响主业务，只记录日志
                        Log::error(
                            '发票开具成功通知发送失败: 发票编号: ' . $res->invoice_no . ' 错误信息: ' . $e->getMessage() .
                                ' | 文件：' . $e->getFile() .
                                ' | 行号：' . $e->getLine()
                        );
                    }

                    $this->logger->logOperation($res->id, 'invoice', '发票-上传发票附件', '发票上传成功');
                }

                $return['code'] = 0;
            } else {
                Db::rollback();
                $return['code'] = 500001;
            }
        } catch (\Throwable $th) {
            Db::rollback();
            $return['code'] = 500001;
            $return['message'] = $th->getMessage();
        }
        return $return;
    }


    /**
     * @describe 批量逻辑删除
     * @author: Bobo
     * @date: 2025-02-08 12:02:32
     * @param [arr] @required $ids ID数组
     * @return Renderable
     */
    public function batchLogicalDelete($ids)
    {
        $idArray = explode(',', $ids);
        $this->model->where('is_del', 0)->where('id', 'in', $ids)->count();
        if ($this->model->where('is_del', 0)->where('id', 'in', $ids)->count() !== count($idArray)) {
            return ['code' => 400000, 'message' => '部分数据不存在或已被删除'];
        }
        $this->model::startTrans();
        try {
            $this->model::where('id', 'in', $ids)->update(['is_del' => time()]);
            foreach ($idArray as $id) {
                $this->logger->logOperation($id, 'invoice', '订单开票', '订单开票信息删除');
            }
            $this->model::commit();
            $return['code'] = 0;
        } catch (\Throwable $th) {
            $this->model::rollback();
            $return['code'] = 500001;
            $return['message'] = $th->getMessage();
        }
        return $return;
    }


    /**
     * 虚拟库存 - 减库存
     * @param int $item 订单明细一条
     * @return array
     */
    public function virtualInventoryReduce(array $que)
    {

        foreach ($que['list'] as  $value) {

            $count_quantity = $value['ship_quantity'];

            if ($count_quantity <= 0) {
                throw new ThrowException([
                    'message' => '数量错误'
                ]);
            }

            // 查询具体库存记录，并加锁
            $inventoryList = Db::name('inventory')
                ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty')
                ->where([
                    'is_del' => 0,
                    'is_sale' => 1,
                    'productid' => $value['product_id'],
                    'arrival_date' => $value['arrival_date'],
                    'is_futures' =>  $value['is_futures'],
                    'wid' =>  $value['wid'],
                    ['available_qty', '>', 0],
                ])
                ->lock(true)
                ->select();

            if (!$inventoryList) {
                throw new ThrowException([
                    'message' => '库存不足'
                ]);
            }

            /* 减可用库存 */
            foreach ($inventoryList as  $inventory) {

                if ($count_quantity <= 0) {
                    break;
                }

                $available_item_qty = $inventory['available_qty'];


                if ($count_quantity <= $available_item_qty) {
                    $available_qty = $count_quantity;
                    $count_quantity = 0;
                } else {
                    $available_qty = $available_item_qty;
                    $count_quantity = $count_quantity - $available_qty;
                }

                /* 更新锁定库存 */
                $result = Db::name('inventory')
                    ->where('id', $inventory['id'])
                    ->dec('available_qty', $available_qty)
                    ->update();

                if (!$result) {
                    throw new ThrowException([
                        'message' => '减库存失败'
                    ]);
                }

                /* 库存日志记录 */
                $log_data = [];
                $log_data['inventory_id'] = $inventory['id'];
                $log_data['business_tabel_name'] = 'order';
                $log_data['business_table_id'] = $que['order_id'];
                $log_data['business'] = '订单发货';
                $log_data['number'] = $available_qty;
                $log_data['remark'] = '虚拟仓库发货减库存';
                $writeRecordLog = new InventoryChangeRecord();
                $writeRecordLog->writeLog($log_data);
            }
        }
    }
}
